package main

import (
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"log"
	"net/http"
	_ "net/http/pprof"
	"time"
)

func main() {

	go http.ListenAndServe(":6060", nil)

	r := gin.Default()
	// wrk -c 1000 -t 4 -d 60s http://localhost:8080/demo1
	r.GET("/demo1", func(c *gin.Context) {
		demo1_1(c)
	})

	// docker run --name pyroscope -p 4040:4040 grafana/pyroscope:latest server
	// 采用主动 push 方式接入 pyroscope
	//_, err := pyroscope.Start(pyroscope.Config{
	//	ApplicationName: "simple.golang.app",
	//
	//	// replace this with the address of pyroscope server
	//	ServerAddress: "http://localhost:4040",
	//
	//	// by default all profilers are enabled,
	//	// but you can select the ones you want to use:
	//	ProfileTypes: []pyroscope.ProfileType{
	//		pyroscope.ProfileCPU,
	//		pyroscope.ProfileAllocObjects,
	//		pyroscope.ProfileAllocSpace,   // 累计分配的总内存量
	//		pyroscope.ProfileInuseObjects, // 当前存活的对象数量
	//		pyroscope.ProfileInuseSpace,   // 当前正在使用的内存量
	//		pyroscope.ProfileGoroutines,
	//	},
	//})
	//
	//if err != nil {
	//	log.Fatal(err)
	//}

	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "在 Pyroscope 中，这些指标用于采集和分析程序的不同性能维度（主要是 CPU 和内存相关），帮助定位性能瓶颈。以下是每个指标的具体含义：\n1. pyroscope.ProfileCPU\n含义：CPU 使用率分析，记录程序中各函数 / 代码段的 CPU 耗时占比。\n作用：能直观反映哪些函数消耗了最多的 CPU 资源，是排查 CPU 使用率过高、函数执行效率低等问题的核心指标。\n采集内容：通过采样调用栈，统计每个函数在 CPU 上的执行时间占比（例如，某函数在 100 次采样中出现 30 次，说明其可能消耗了约 30% 的 CPU）。\n2. pyroscope.ProfileAllocObjects\n含义：内存分配对象数量分析，记录程序运行中各函数分配的对象（如 Go 中的 new、make 创建的对象）总数。\n作用：用于定位 “频繁创建对象” 的函数，这类函数可能导致 GC（垃圾回收）压力增大，间接影响性能。\n示例：若某函数在采样周期内被统计到分配了 10 万个对象，可能意味着该函数存在不必要的对象创建（如循环内重复分配）。\n3. pyroscope.ProfileAllocSpace\n含义：内存分配空间大小分析，记录各函数分配的内存总字节数（累计分配量，包括已被 GC 回收的内存）。\n作用：识别 “内存分配大户”，即哪些函数分配了最多的内存（无论是否已回收），帮助优化内存分配效率。\n与 AllocObjects 的区别：前者统计 “对象数量”，后者统计 “总字节数”（例如，分配 1 个 1MB 的切片和 1000 个 1KB 的对象，AllocObjects 差异大，但 AllocSpace 可能接近）。\n4. pyroscope.ProfileInuseObjects\n含义：当前正在使用的对象数量分析，记录采样时刻各函数创建的、尚未被 GC 回收的对象总数。\n作用：反映 “内存持有量”，用于定位 “内存泄漏” 或 “长期占用大量对象” 的函数（例如，未释放的缓存、全局变量累积的对象）。\n特点：关注 “存活对象”，若某函数的 InuseObjects 持续增长且不下降，可能存在内存泄漏风险。\n5. pyroscope.ProfileInuseSpace\n含义：当前正在使用的内存空间大小分析，记录采样时刻各函数创建的、尚未被 GC 回收的内存总字节数。\n作用：与 InuseObjects 类似，但从 “字节数” 角度反映当前内存占用，更直观体现内存消耗的实际规模。\n示例：若某函数的 InuseSpace 长期保持在 1GB 以上，说明其持有大量内存，可能需要优化（如减少缓存大小、及时释放资源）。\n总结\n这些指标从 CPU 耗时 和 内存分配 / 占用 两个核心维度分析程序性能：\nCPU 相关（ProfileCPU）：定位计算密集型瓶颈。\n内存相关（后四个）：\nAlloc* 系列：关注 “分配行为”（累计分配量），优化内存分配效率。\nInuse* 系列：关注 “当前持有量”，排查内存泄漏或过度占用问题。\n实际使用时，可根据需求组合启用（例如，排查内存泄漏优先用 InuseObjects 和 InuseSpace，优化 CPU 瓶颈优先用 ProfileCPU）。在 Pyroscope 中，这些指标用于采集和分析程序的不同性能维度（主要是 CPU 和内存相关），帮助定位性能瓶颈。以下是每个指标的具体含义：\n1. pyroscope.ProfileCPU\n含义：CPU 使用率分析，记录程序中各函数 / 代码段的 CPU 耗时占比。\n作用：能直观反映哪些函数消耗了最多的 CPU 资源，是排查 CPU 使用率过高、函数执行效率低等问题的核心指标。\n采集内容：通过采样调用栈，统计每个函数在 CPU 上的执行时间占比（例如，某函数在 100 次采样中出现 30 次，说明其可能消耗了约 30% 的 CPU）。\n2. pyroscope.ProfileAllocObjects\n含义：内存分配对象数量分析，记录程序运行中各函数分配的对象（如 Go 中的 new、make 创建的对象）总数。\n作用：用于定位 “频繁创建对象” 的函数，这类函数可能导致 GC（垃圾回收）压力增大，间接影响性能。\n示例：若某函数在采样周期内被统计到分配了 10 万个对象，可能意味着该函数存在不必要的对象创建（如循环内重复分配）。\n3. pyroscope.ProfileAllocSpace\n含义：内存分配空间大小分析，记录各函数分配的内存总字节数（累计分配量，包括已被 GC 回收的内存）。\n作用：识别 “内存分配大户”，即哪些函数分配了最多的内存（无论是否已回收），帮助优化内存分配效率。\n与 AllocObjects 的区别：前者统计 “对象数量”，后者统计 “总字节数”（例如，分配 1 个 1MB 的切片和 1000 个 1KB 的对象，AllocObjects 差异大，但 AllocSpace 可能接近）。\n4. pyroscope.ProfileInuseObjects\n含义：当前正在使用的对象数量分析，记录采样时刻各函数创建的、尚未被 GC 回收的对象总数。\n作用：反映 “内存持有量”，用于定位 “内存泄漏” 或 “长期占用大量对象” 的函数（例如，未释放的缓存、全局变量累积的对象）。\n特点：关注 “存活对象”，若某函数的 InuseObjects 持续增长且不下降，可能存在内存泄漏风险。\n5. pyroscope.ProfileInuseSpace\n含义：当前正在使用的内存空间大小分析，记录采样时刻各函数创建的、尚未被 GC 回收的内存总字节数。\n作用：与 InuseObjects 类似，但从 “字节数” 角度反映当前内存占用，更直观体现内存消耗的实际规模。\n示例：若某函数的 InuseSpace 长期保持在 1GB 以上，说明其持有大量内存，可能需要优化（如减少缓存大小、及时释放资源）。\n总结\n这些指标从 CPU 耗时 和 内存分配 / 占用 两个核心维度分析程序性能：\nCPU 相关（ProfileCPU）：定位计算密集型瓶颈。\n内存相关（后四个）：\nAlloc* 系列：关注 “分配行为”（累计分配量），优化内存分配效率。\nInuse* 系列：关注 “当前持有量”，排查内存泄漏或过度占用问题。\n实际使用时，可根据需求组合启用（例如，排查内存泄漏优先用 InuseObjects 和 InuseSpace，优化 CPU 瓶颈优先用 ProfileCPU）。")
	})

	// wrk -c 10 -t 2 -d 60s http://localhost:8080/demo1
	r.GET("/demo11", func(c *gin.Context) {
		InitServiceWrong()
	})

	// wrk -c 10 -t 4 -d 60s http://localhost:8080/demo2
	r.GET("/demo21", func(c *gin.Context) {
		resp, err := http.Get("http://localhost:8080/ping")
		if err != nil {
			return
		}
		//defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return
		}

		c.String(http.StatusOK, string(body))
	})

	// wrk -c 1000 -t 4 -d 60s http://localhost:8080/demo3
	r.GET("/demo31", AsyncLogMiddleware(), func(c *gin.Context) {

		c.String(http.StatusOK, "OK")
	})

	r.Run()
}

func AsyncLogMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		// 启动协程记录日志，但c.Request.Context()可能已失效
		go func() {
			time.Sleep(3 * time.Second) // 模拟处理延迟
			log.Printf("Request %s %s took %v", c.Request.Method, c.Request.URL.Path, time.Since(start))
		}()
		c.Next()
	}
}
